package com.czapl.mygdxgame;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.graphics.glutils.ShapeRenderer;
import com.badlogic.gdx.graphics.glutils.ShapeRenderer.ShapeType;
import com.badlogic.gdx.maps.MapProperties;
import com.badlogic.gdx.maps.tiled.TiledMap;
import com.badlogic.gdx.maps.tiled.TiledMapTile;
import com.badlogic.gdx.maps.tiled.TiledMapTileLayer;
import com.badlogic.gdx.maps.tiled.TmxMapLoader;
import com.badlogic.gdx.maps.tiled.TiledMapTileLayer.Cell;
import com.badlogic.gdx.maps.tiled.renderers.OrthogonalTiledMapRenderer;
import com.badlogic.gdx.maps.tiled.tiles.AnimatedTiledMapTile;
import com.badlogic.gdx.maps.tiled.tiles.StaticTiledMapTile;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.scenes.scene2d.Actor;
import com.badlogic.gdx.scenes.scene2d.Stage;
import com.badlogic.gdx.utils.Array;
import com.czapl.api.IFieldSelectionListener;
import com.czapl.api.ITower;
import com.czapl.api.IUnit;
import com.czapl.api.IUnit.IUnitTargetReachedListener;
import com.czapl.drawing.CUnit;

public class GameBoard extends Stage implements IUnitTargetReachedListener {
	
	public static final String CELL_KEY_SOURCE = "source";
	public static final String CELL_KEY_SINK = "sink";
	public static int TILE_SIZE;
	
	private Array<ConstructableField> m_constructableFields = new Array<ConstructableField>();
	private Array<IUnit> m_units = new Array<IUnit>();
	private Array<ITower> m_towers = new Array<ITower>();
	private TiledMap m_map;
	private OrthogonalTiledMapRenderer m_mapRenderer;
	private TiledMapTileLayer m_tileBackgroundLayer;
	private CellCoordinates m_sourceCellCoordinates;
	private CellCoordinates m_sinkCellCoordinates;
	private List<CellCoordinates> m_path;
	private int mapPixelWidth, mapPixelHeight;
	private IFieldSelectionListener m_listener;
	private ShapeRenderer m_shapeRenderer;
	
	public GameBoard( IFieldSelectionListener listener) {
		m_listener = listener;
		m_map = new TmxMapLoader().load("maps/map1.tmx");
		MapProperties prop = m_map.getProperties();		
		int mapWidth = prop.get("width", Integer.class);
		int mapHeight = prop.get("height", Integer.class);
		TILE_SIZE = prop.get("tilewidth", Integer.class);
		mapPixelWidth = mapWidth*TILE_SIZE;
		mapPixelHeight = mapHeight*TILE_SIZE;
		
		m_mapRenderer = new OrthogonalTiledMapRenderer(m_map);	
		m_path = new ArrayList<CellCoordinates>();
		
		m_shapeRenderer = new ShapeRenderer();
		//ANIMATED TILES
        Array<StaticTiledMapTile> frameTiles = new Array<StaticTiledMapTile>();
        Iterator<TiledMapTile> tiles = m_map.getTileSets().getTileSet("tileset").iterator();
        while(tiles.hasNext()){
        	TiledMapTile tile = tiles.next();
        	if(tile.getProperties().containsKey("animation")) {
        		frameTiles.add((StaticTiledMapTile) tile);
        	}
        }
        
        AnimatedTiledMapTile animatedTile = new AnimatedTiledMapTile(1/3f, frameTiles);
        m_tileBackgroundLayer = (TiledMapTileLayer) m_map.getLayers().get("background");	
        
        for(int x=0; x<m_tileBackgroundLayer.getWidth(); x++) {
        	for(int y=0; y<m_tileBackgroundLayer.getHeight(); y++) {
        		Cell cell = m_tileBackgroundLayer.getCell(x, y);
        		if(cell.getTile().getProperties().containsKey("animation")) {
        			cell.setTile(animatedTile);
        		}
        		if(0 == getTileType(cell.getTile())) {
            		System.out.println("("+x+","+y+") is constructable");
                	addConstructableField(new ConstructableField(new CellCoordinates(x,y)));
            	}
        	}
        }
        
        getSpawnTargetCellCoordinates();
        discoverPath();
	}
	
//	@Override
//	public void act (float delta) {
//		super.act(delta);
//
//	}
	
	@Override
	public void draw() {
		renderMap();
		super.draw();
		drawConditionBars();
		m_shapeRenderer.setProjectionMatrix(getCamera().combined);
		m_shapeRenderer.setColor(Color.PINK);
		m_shapeRenderer.begin(ShapeType.Line);
		for(ITower tower: m_towers) {
			IUnit aimedUnit = tower.getAimedUnit();
			if(aimedUnit != null) {
				m_shapeRenderer.line(tower.getPosition().x, tower.getPosition().y, aimedUnit.getPosition().x, aimedUnit.getPosition().y);
			}
		}
		m_shapeRenderer.end();
	}
	
	private void getSpawnTargetCellCoordinates() {
		int cellX, cellY;
		for(cellX=0; cellX<m_tileBackgroundLayer.getWidth(); cellX++) {
			for(cellY=0; cellY<m_tileBackgroundLayer.getHeight(); cellY++) {
				//System.out.println("cell["+cellY+","+cellX+"]");
				Cell cell = m_tileBackgroundLayer.getCell(cellX, cellY);
				if(cell.getTile().getProperties().containsKey(CELL_KEY_SOURCE)) {
					if(null == m_sourceCellCoordinates) {
						System.out.println("m_spawnCellCoordinates = ["+cellX+","+cellY+"]");
						m_sourceCellCoordinates = new CellCoordinates(cellX, cellY);
					}
					else {
						System.out.println("m_spawnCellCoordinates duplicate!");
					}
				}
				if(cell.getTile().getProperties().containsKey(CELL_KEY_SINK)) {
					if(null == m_sinkCellCoordinates) {
						System.out.println("m_targetCellCoordinates = ["+cellX+","+cellY+"]");
						m_sinkCellCoordinates = new CellCoordinates(cellX, cellY);
					}
					else {
						System.out.println("m_targetCellCoordinates duplicate!");
					}
				}
			}
		}
	}
	
	private void discoverPath() {
		CellCoordinates previousCellCoordinates = m_sourceCellCoordinates.clone();
		CellCoordinates currentCellCoordinates = previousCellCoordinates.clone();
		CellCoordinates nextCellCoordinates = m_sourceCellCoordinates.clone();
		m_path.add(nextCellCoordinates);
		while(!nextCellCoordinates.equals(m_sinkCellCoordinates)) {
			System.out.println("next cell ("+nextCellCoordinates.getX()+","+nextCellCoordinates.getY()+")");
			nextCellCoordinates = getNextCellCoordinates(previousCellCoordinates, currentCellCoordinates);
			m_path.add(nextCellCoordinates);
			previousCellCoordinates.assign(currentCellCoordinates);
			currentCellCoordinates.assign(nextCellCoordinates);
		}
	}
	
	public List<CellCoordinates> getPath() {
		return m_path;
	}
	
	private CellCoordinates getNextCellCoordinates(CellCoordinates previousCellCoordinates, CellCoordinates currentCellCoordinates)
	{
		Cell previousCell, nextCell;
		CellCoordinates nextCellCoordinates = new CellCoordinates(0,0);
		int cellX = currentCellCoordinates.getX();
		int cellY = currentCellCoordinates.getY();
		previousCell = m_tileBackgroundLayer.getCell(previousCellCoordinates.getX(), previousCellCoordinates.getY());
		//System.out.println("searching path");
		nextCell = m_tileBackgroundLayer.getCell(cellX+1, cellY);
		if(isCellCrossable(nextCell)) {
			if(nextCell != previousCell) {
				//System.out.println("right");
				//updateDirection(MovementDirection.RIGHT);
				nextCellCoordinates.set(cellX+1, cellY);
				return nextCellCoordinates;
			}
		}
		nextCell = m_tileBackgroundLayer.getCell(cellX, cellY+1);
		if(isCellCrossable(nextCell)) {
			if(nextCell != previousCell) {
				//System.out.println("up");
				//updateDirection(MovementDirection.TOP);
				nextCellCoordinates.set(cellX, cellY+1);
				return nextCellCoordinates;
			}
		}
		nextCell = m_tileBackgroundLayer.getCell(cellX, cellY-1);
		if(isCellCrossable(nextCell)) {
			if(nextCell != previousCell) {
				//System.out.println("down");
				//updateDirection(MovementDirection.BOTTOM);
				nextCellCoordinates.set(cellX, cellY-1);
				return nextCellCoordinates;
			}
		}
		nextCell = m_tileBackgroundLayer.getCell(cellX-1, cellY);
		if(isCellCrossable(nextCell)) {
			if(nextCell != previousCell) {
				//System.out.println("left");
				//updateDirection(MovementDirection.LEFT);
				nextCellCoordinates.set(cellX-1, cellY);
				return nextCellCoordinates;
			}
		}
		System.out.println("Stopping!");
		return nextCellCoordinates;
		//m_objectLayer.getCell(m_cellX-1, m_cellY)
	}
	
	private boolean isCellCrossable(Cell cell) {
		if(cell == null) {
			System.out.println("cell is null");
			return false;
		}
		int type = getTileType(cell.getTile());
		if(type == -1) {
			System.out.println("cell does not contain parameter type");
			return false;
		}
		//System.out.println("cell is of type: "+type);
		if(type == 2) {
			//System.out.println("cell is crossable");
			return true;
		}
		//System.out.println("cell is uncrossable");
		return false;
	}
	
	private int getTileType(TiledMapTile tile) {
		int type;
		String typeStr = (String) tile.getProperties().get("type");
		if(typeStr == null) {
			type = -1;
		}
		else {
			type = Integer.parseInt(typeStr);
		}
		return type;
	}
	
	public CellCoordinates getSpawnCellCoordinates() {
		return m_sourceCellCoordinates;
	}
	
	public CellCoordinates getSinkCellCoordinates() {
		return m_sinkCellCoordinates;
	}
	
	private void renderMap() {
		m_mapRenderer.setView((OrthographicCamera)getCamera());
		m_mapRenderer.render();
	}
	
	private void addConstructableField(ConstructableField field) {
		m_constructableFields.add(field);
		field.setFieldSelectionListener(m_listener);
		addActor(field);
		field.setX(field.getCoordinates().getX()*TILE_SIZE);
		field.setY(field.getCoordinates().getY()*TILE_SIZE);
	}
	
	public int getTileSize() {
		return TILE_SIZE;
	}
	
	public Vector2 getMapSize() {
		return new Vector2(mapPixelWidth, mapPixelHeight);
	}
	
	public void addUnit(IUnit unit) {
		m_units.add(unit);
		unit.setCellChangeListener(this);
		addActor((Actor) unit);
	}
	
	public void addTower(ITower towerPattern, ConstructableField field) {
		ITower tower = towerPattern.clone();
		tower.setPosition(field.getCoordinates().getX()*TILE_SIZE, field.getCoordinates().getY()*TILE_SIZE);
		addActor((Actor) tower);
		if(field.addTower(tower)) {
			m_towers.add(tower);
		}
	}
	
	public void setFieldsHighlighted(boolean highlighted, boolean constructableOnly) {
		for(ConstructableField field : m_constructableFields) {
			if(constructableOnly) {
				if(field.getTower() == null) {
					field.setHighlighted(highlighted);
				}
			}
			else {
				field.setHighlighted(highlighted);
			}

		}
	}
	
	private void drawConditionBars() {
		for(IUnit unit : m_units) {
			unit.drawConditionBar();
		}
	}
	
	public Array<IUnit> getUnits() {
		return m_units;
	}

	@Override
	public void onTargetReached(IUnit unit) {
			System.out.println("Target reached callback");
	}
	

	
}
